package com.ssy.lingxi.enhance.serviceimpl.supplier;

import cn.hutool.core.collection.CollectionUtil;
import com.querydsl.core.BooleanBuilder;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.enhance.constant.PNOAllStatusEnum;
import com.ssy.lingxi.enhance.constant.PNOOuterStatusEnum;
import com.ssy.lingxi.enhance.constant.PNOSupplierInnerStatusEnum;
import com.ssy.lingxi.enhance.constant.RoleTypeEnum;
import com.ssy.lingxi.enhance.entity.InnerWorkflowRecordDO;
import com.ssy.lingxi.enhance.entity.OuterWorkflowRecordDO;
import com.ssy.lingxi.enhance.entity.ProduceNoticeOrderDO;
import com.ssy.lingxi.enhance.entity.QProduceNoticeOrderDO;
import com.ssy.lingxi.enhance.handler.async.MessageAsyncService;
import com.ssy.lingxi.enhance.handler.async.ReportAsyncService;
import com.ssy.lingxi.enhance.handler.jpa.QueryDslUtil;
import com.ssy.lingxi.enhance.model.dto.CommonIdDTO;
import com.ssy.lingxi.enhance.model.dto.CommonIdListDTO;
import com.ssy.lingxi.enhance.model.qo.ProduceNoticeOrderQO;
import com.ssy.lingxi.enhance.model.vo.ProduceNoticeOrderListVO;
import com.ssy.lingxi.enhance.repository.InnerWorkflowRecordRepository;
import com.ssy.lingxi.enhance.repository.OuterWorkflowRecordRepository;
import com.ssy.lingxi.enhance.repository.ProduceNoticeOrderRepository;
import com.ssy.lingxi.enhance.service.supplier.SupplierToBeSubmitService;
import com.ssy.lingxi.message.api.constant.MessageTemplateCode;
import com.ssy.lingxi.message.api.vo.request.SystemMessageRequest;
import com.ssy.lingxi.report.api.enums.EnhanceProcessOperateTypeEnum;
import com.ssy.lingxi.report.api.enums.EnhanceSupplierOperateTypeEnum;
import com.ssy.lingxi.report.api.enums.OperateDataSourceEnum;
import com.ssy.lingxi.report.api.vo.request.OperateNoticeVO;
import com.ssy.lingxi.workflow.api.feign.ProcessFeign;
import com.ssy.lingxi.workflow.api.model.contant.ProcessTaskStatusEnum;
import com.ssy.lingxi.workflow.api.model.vo.request.TaskExecuteVO;
import com.ssy.lingxi.workflow.api.model.vo.request.TaskStartVO;
import com.ssy.lingxi.workflow.api.model.vo.response.SimpleTaskCompleteVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 加工能力 - 指派生产通知单(供应商) - 待提交生产通知单 - 业务实现层
 * @author fhj
 * @date 2020/10/20
 * @version 2.0.0
 */
@Slf4j
@Service
public class SupplierToBeSubmitServiceImpl implements SupplierToBeSubmitService {

    @Resource
    private ProcessFeign processFeign;
    @Resource
    private QueryDslUtil queryDslUtil;
    @Resource
    private ProduceNoticeOrderRepository produceNoticeOrderRepository;
    @Resource
    private InnerWorkflowRecordRepository innerWorkflowRecordRepository;
    @Resource
    private OuterWorkflowRecordRepository outerWorkflowRecordRepository;
    @Resource
    private ReportAsyncService reportAsyncService;
    @Resource
    private MessageAsyncService messageAsyncService;

    /**
     * 列表
     * */
    @Override
    public Wrapper<PageData<ProduceNoticeOrderListVO>> list(ProduceNoticeOrderQO qo, UserLoginCacheDTO user) {
        //查询表实体 - 生产通知单
        QProduceNoticeOrderDO pno = QProduceNoticeOrderDO.produceNoticeOrderDO;

        //查询条件构造 - 必要条件
        BooleanBuilder predicates = new BooleanBuilder();
        predicates.and(pno.supplierMemberId.eq(user.getMemberId()));
        predicates.and(pno.supplierRoleId.eq(user.getMemberRoleId()));
        predicates.and(pno.outerStatus.eq(PNOOuterStatusEnum.TO_BE_SUBMIT.getCode()));
        predicates.and(pno.supplierInnerStatus.eq(PNOSupplierInnerStatusEnum.TO_BE_SUBMIT.getCode()));

        return Wrapper.success(queryDslUtil.getSupplierPNOList(qo, pno, predicates));
    }

    /**
     * 提交
     * */
    @Override
    @Transactional
    public Wrapper<Void> submit(CommonIdDTO dto, UserLoginCacheDTO user) {
        //根据ID获取生产通知单详情
        ProduceNoticeOrderDO produceNoticeOrder = produceNoticeOrderRepository.findById(dto.getId()).orElse(null);
        if(produceNoticeOrder == null) {
            return Wrapper.fail(ResponseCode.ENHANCE_BY_ID_NOT_FOUND_PNO);
        }
        if(!produceNoticeOrder.getStatus().equals(PNOAllStatusEnum.TO_BE_SUPPLIER_SUBMIT.getCode())) {
            return Wrapper.fail(ResponseCode.ENHANCE_ONLY_SUBMIT_INNER_STATUS_AS_TO_BE_SUPPLIER_SUBMIT);
        }

        //定义OperateNoticeVO集合
        List<OperateNoticeVO> noticeVOList = new ArrayList<>();

        //调用工作流服务 -> 执行供应商内部流程
        TaskExecuteVO taskExecuteVO = new TaskExecuteVO();
        taskExecuteVO.setMemberId(produceNoticeOrder.getSupplierMemberId());
        taskExecuteVO.setRoleId(produceNoticeOrder.getSupplierRoleId());
        taskExecuteVO.setDataId(produceNoticeOrder.getId());
        taskExecuteVO.setTaskId(produceNoticeOrder.getSupplierInnerTaskId());
        taskExecuteVO.setAgree(ProcessTaskStatusEnum.GOTO_NEXT_STEP.getCode());
        taskExecuteVO.setProcessKey(produceNoticeOrder.getSupplierInnerProcessKey());
        Wrapper<SimpleTaskCompleteVO> supplierWrapper = processFeign.completeSimpleTask(taskExecuteVO);
        if(ResponseCode.SUCCESS.getCode() == supplierWrapper.getCode()) {
            //记录供应商内部工作流记录
            InnerWorkflowRecordDO innerWorkflowRecord = new InnerWorkflowRecordDO();
            innerWorkflowRecord.setProduceNoticeOrderId(produceNoticeOrder.getId());
            innerWorkflowRecord.setUserId(user.getUserId());
            innerWorkflowRecord.setMemberId(user.getMemberId());
            innerWorkflowRecord.setRoleId(user.getMemberRoleId());
            innerWorkflowRecord.setType(RoleTypeEnum.SUPPLIER.getCode());
            innerWorkflowRecord.setStep(produceNoticeOrder.getSupplierInnerStatus());
            innerWorkflowRecord.setOperator(user.getUserName());
            innerWorkflowRecord.setDepartment(user.getUserOrgName());
            innerWorkflowRecord.setJobTitle(user.getUserJobTitle());
            innerWorkflowRecord.setStatus("已提交");
            innerWorkflowRecord.setOperate("提交生产通知单");
            innerWorkflowRecord.setOperateTime(System.currentTimeMillis());
            innerWorkflowRecord.setOpinion("");

            //调用工作流服务 -> 开启加工企业内部工作流
            TaskStartVO taskStartVO = new TaskStartVO();
            taskStartVO.setProcessKey(produceNoticeOrder.getProcessInnerProcessKey());
            taskStartVO.setMemberId(produceNoticeOrder.getProcessMemberId());
            taskStartVO.setRoleId(produceNoticeOrder.getProcessRoleId());
            taskStartVO.setDataId(produceNoticeOrder.getId());
            Wrapper<SimpleTaskCompleteVO> processWrapper = processFeign.startSimpleProcess(taskStartVO);
            if(ResponseCode.SUCCESS.getCode() == processWrapper.getCode()) {
                //更新状态、供应商内部状态、供应商内部任务ID、加工企业内部状态、加工企业内部任务ID
                produceNoticeOrder.setStatus(PNOAllStatusEnum.TO_BE_PROCESS_SUBMIT_EXAM.getCode());
                produceNoticeOrder.setSupplierInnerStatus(supplierWrapper.getData().getStatus());
                produceNoticeOrder.setSupplierInnerTaskId(supplierWrapper.getData().getTaskId());
                produceNoticeOrder.setProcessInnerStatus(processWrapper.getData().getStatus());
                produceNoticeOrder.setProcessInnerTaskId(processWrapper.getData().getTaskId());

                //调用工作流服务 -> 执行外部流程
                taskExecuteVO = new TaskExecuteVO();
                taskExecuteVO.setMemberId(produceNoticeOrder.getSupplierMemberId());
                taskExecuteVO.setRoleId(produceNoticeOrder.getSupplierRoleId());
                taskExecuteVO.setDataId(produceNoticeOrder.getId());
                taskExecuteVO.setTaskId(produceNoticeOrder.getOuterTaskId());
                taskExecuteVO.setAgree(ProcessTaskStatusEnum.GOTO_NEXT_STEP.getCode());
                taskExecuteVO.setProcessKey(produceNoticeOrder.getOuterProcessKey());
                Wrapper<SimpleTaskCompleteVO> outerWrapper = processFeign.completeSimpleTask(taskExecuteVO);
                if(ResponseCode.SUCCESS.getCode() == outerWrapper.getCode()) {
                    //保存供应商内部工作流记录
                    innerWorkflowRecordRepository.saveAndFlush(innerWorkflowRecord);

                    //记录外部工作流记录
                    OuterWorkflowRecordDO outerWorkflowRecordDO = new OuterWorkflowRecordDO();
                    outerWorkflowRecordDO.setProduceNoticeOrderId(produceNoticeOrder.getId());
                    outerWorkflowRecordDO.setUserId(user.getUserId());
                    outerWorkflowRecordDO.setMemberId(user.getMemberId());
                    outerWorkflowRecordDO.setRoleId(user.getMemberRoleId());
                    outerWorkflowRecordDO.setStep(produceNoticeOrder.getOuterStatus());
                    outerWorkflowRecordDO.setRoleName(user.getMemberRoleName());
                    outerWorkflowRecordDO.setStatus("待确认");
                    outerWorkflowRecordDO.setOperate("提交生产通知单");
                    outerWorkflowRecordDO.setOperateTime(System.currentTimeMillis());
                    outerWorkflowRecordDO.setOpinion("");
                    outerWorkflowRecordRepository.saveAndFlush(outerWorkflowRecordDO);

                    //更新外部状态、外部任务ID
                    produceNoticeOrder.setOuterStatus(outerWrapper.getData().getStatus());
                    produceNoticeOrder.setOuterTaskId(outerWrapper.getData().getTaskId());
                    produceNoticeOrderRepository.saveAndFlush(produceNoticeOrder);
                }else {
                    log.error("执行外部工作流程任务失败, 导致生产通知单的任务ID与工作流服务的任务ID不匹配【异常生产通知单】");
                    log.error("工作流服务异常:" + outerWrapper.getMessage());
                    throw new BusinessException(ResponseCode.ENHANCE_WORKFLOW_ERROR);
                }
            }else {
                log.error("开启加工企业内部工作流失败, 导致生产通知单的任务ID与工作流服务的任务ID不匹配【异常生产通知单】");
                log.error("工作流服务异常:" + processWrapper.getMessage());
                throw new BusinessException(ResponseCode.ENHANCE_WORKFLOW_ERROR);
            }
        }else {
            log.error("工作流服务异常:" + supplierWrapper.getMessage());
            throw new BusinessException(ResponseCode.ENHANCE_WORKFLOW_ERROR);
        }

        //指派生产通知单 - 待确认生产通知单 - 待办减1
        OperateNoticeVO supplierNoticeVO = new OperateNoticeVO();
        supplierNoticeVO.setMemberId(user.getMemberId());
        supplierNoticeVO.setRoleId(user.getMemberRoleId());
        supplierNoticeVO.setDataSource(OperateDataSourceEnum.ENHANCE_SUPPLIER.getCode());
        supplierNoticeVO.setReduceOperateType(EnhanceSupplierOperateTypeEnum.TO_BE_COMMIT.getCode());
        supplierNoticeVO.setReduceCount(1L);
        noticeVOList.add(supplierNoticeVO);
        //确认生产通知单 - 待提交审核生产通知单 - 待办加1
        OperateNoticeVO processNoticeVO = new OperateNoticeVO();
        processNoticeVO.setMemberId(produceNoticeOrder.getProcessMemberId());
        processNoticeVO.setRoleId(produceNoticeOrder.getProcessRoleId());
        processNoticeVO.setDataSource(OperateDataSourceEnum.ENHANCE_PROCESS.getCode());
        processNoticeVO.setIncreaseOperateType(EnhanceProcessOperateTypeEnum.TO_BE_VALIFY_COMMIT.getCode());
        processNoticeVO.setIncreaseCount(1L);
        noticeVOList.add(processNoticeVO);

        //调用报表服务、消息服务 -> 批量新增操作通知、发送系统消息（如果调用过程出现异常, 无需回滚, 直接catch打印日志正常返回。）
        reportAsyncService.addOperateNoticeList(noticeVOList);
        messageAsyncService.sendSystemMessage(produceNoticeOrder.getProcessMemberId(), produceNoticeOrder.getProcessRoleId(),
                MessageTemplateCode.production_order_handle_wait_audit, Stream.of(produceNoticeOrder.getNoticeNo(), produceNoticeOrder.getSummary()).collect(Collectors.toList())
        );

        return Wrapper.success();
    }

    /**
     * 批量提交
     * */
    @Override
    @Transactional
    public Wrapper<Void> batchSubmit(CommonIdListDTO dto, UserLoginCacheDTO user) {
        //根据ID集合获取生产通知单集合
        List<ProduceNoticeOrderDO> produceNoticeOrderList = produceNoticeOrderRepository.findAllById(dto.getIdList());

        //定义OperateNoticeVO集合（新增操作通知）、SystemMessageRequest集合（发送系统消息）
        List<OperateNoticeVO> noticeVOList = new ArrayList<>();
        List<SystemMessageRequest> systemMessageRequestList = new ArrayList<>();

        //校验
        if(CollectionUtil.isEmpty(produceNoticeOrderList)) {
            return Wrapper.fail(ResponseCode.ENHANCE_BY_ID_NOT_FOUND_PNO);
        }
        if(produceNoticeOrderList.stream().anyMatch(a -> !a.getStatus().equals(PNOAllStatusEnum.TO_BE_SUPPLIER_SUBMIT.getCode()))) {
            return Wrapper.fail(ResponseCode.ENHANCE_ONLY_SUBMIT_INNER_STATUS_AS_TO_BE_SUPPLIER_SUBMIT);
        }

        //循环调用工作流服务, 调用成功时更新生产通知单, 调用失败直接返回, 不需要抛出异常, 因为前面调用成功的不需要回滚。
        for(ProduceNoticeOrderDO p:produceNoticeOrderList) {
            //调用工作流服务 -> 执行供应商内部流程
            TaskExecuteVO taskExecuteVO = new TaskExecuteVO();
            taskExecuteVO.setMemberId(p.getSupplierMemberId());
            taskExecuteVO.setRoleId(p.getSupplierRoleId());
            taskExecuteVO.setDataId(p.getId());
            taskExecuteVO.setTaskId(p.getSupplierInnerTaskId());
            taskExecuteVO.setAgree(ProcessTaskStatusEnum.GOTO_NEXT_STEP.getCode());
            taskExecuteVO.setProcessKey(p.getSupplierInnerProcessKey());
            Wrapper<SimpleTaskCompleteVO> supplierWrapper = processFeign.completeSimpleTask(taskExecuteVO);
            if(ResponseCode.SUCCESS.getCode() == supplierWrapper.getCode()) {
                //记录供应商内部工作流记录
                InnerWorkflowRecordDO innerWorkflowRecord = new InnerWorkflowRecordDO();
                innerWorkflowRecord.setProduceNoticeOrderId(p.getId());
                innerWorkflowRecord.setUserId(user.getUserId());
                innerWorkflowRecord.setMemberId(user.getMemberId());
                innerWorkflowRecord.setRoleId(user.getMemberRoleId());
                innerWorkflowRecord.setType(RoleTypeEnum.SUPPLIER.getCode());
                innerWorkflowRecord.setStep(p.getSupplierInnerStatus());
                innerWorkflowRecord.setOperator(user.getUserName());
                innerWorkflowRecord.setDepartment(user.getUserOrgName());
                innerWorkflowRecord.setJobTitle(user.getUserJobTitle());
                innerWorkflowRecord.setStatus("已提交");
                innerWorkflowRecord.setOperate("提交生产通知单");
                innerWorkflowRecord.setOperateTime(System.currentTimeMillis());
                innerWorkflowRecord.setOpinion("");

                //调用工作流服务 -> 开启加工企业内部工作流
                TaskStartVO taskStartVO = new TaskStartVO();
                taskStartVO.setProcessKey(p.getProcessInnerProcessKey());
                taskStartVO.setMemberId(p.getProcessMemberId());
                taskStartVO.setRoleId(p.getProcessRoleId());
                taskStartVO.setDataId(p.getId());
                Wrapper<SimpleTaskCompleteVO> processWrapper = processFeign.startSimpleProcess(taskStartVO);
                if(ResponseCode.SUCCESS.getCode() == processWrapper.getCode()) {
                    //更新状态、供应商内部状态、供应商内部任务ID、加工企业内部状态、加工企业内部任务ID
                    p.setStatus(PNOAllStatusEnum.TO_BE_PROCESS_SUBMIT_EXAM.getCode());
                    p.setSupplierInnerStatus(supplierWrapper.getData().getStatus());
                    p.setSupplierInnerTaskId(supplierWrapper.getData().getTaskId());
                    p.setProcessInnerStatus(processWrapper.getData().getStatus());
                    p.setProcessInnerTaskId(processWrapper.getData().getTaskId());

                    //调用工作流服务 -> 执行外部流程
                    taskExecuteVO = new TaskExecuteVO();
                    taskExecuteVO.setMemberId(p.getSupplierMemberId());
                    taskExecuteVO.setRoleId(p.getSupplierRoleId());
                    taskExecuteVO.setDataId(p.getId());
                    taskExecuteVO.setTaskId(p.getOuterTaskId());
                    taskExecuteVO.setAgree(ProcessTaskStatusEnum.GOTO_NEXT_STEP.getCode());
                    taskExecuteVO.setProcessKey(p.getOuterProcessKey());
                    Wrapper<SimpleTaskCompleteVO> outerWrapper = processFeign.completeSimpleTask(taskExecuteVO);
                    if(ResponseCode.SUCCESS.getCode() == outerWrapper.getCode()) {
                        //保存供应商内部工作流记录
                        innerWorkflowRecordRepository.saveAndFlush(innerWorkflowRecord);

                        //记录外部工作流记录
                        OuterWorkflowRecordDO outerWorkflowRecordDO = new OuterWorkflowRecordDO();
                        outerWorkflowRecordDO.setProduceNoticeOrderId(p.getId());
                        outerWorkflowRecordDO.setUserId(user.getUserId());
                        outerWorkflowRecordDO.setMemberId(user.getMemberId());
                        outerWorkflowRecordDO.setRoleId(user.getMemberRoleId());
                        outerWorkflowRecordDO.setStep(p.getOuterStatus());
                        outerWorkflowRecordDO.setRoleName(user.getMemberRoleName());
                        outerWorkflowRecordDO.setStatus("待确认");
                        outerWorkflowRecordDO.setOperate("提交生产通知单");
                        outerWorkflowRecordDO.setOperateTime(System.currentTimeMillis());
                        outerWorkflowRecordDO.setOpinion("");
                        outerWorkflowRecordRepository.saveAndFlush(outerWorkflowRecordDO);

                        //更新外部状态、外部任务ID
                        p.setOuterStatus(outerWrapper.getData().getStatus());
                        p.setOuterTaskId(outerWrapper.getData().getTaskId());
                        produceNoticeOrderRepository.saveAndFlush(p);

                        //指派生产通知单 - 待确认生产通知单 - 待办减1
                        OperateNoticeVO supplierNoticeVO = new OperateNoticeVO();
                        supplierNoticeVO.setMemberId(user.getMemberId());
                        supplierNoticeVO.setRoleId(user.getMemberRoleId());
                        supplierNoticeVO.setDataSource(OperateDataSourceEnum.ENHANCE_SUPPLIER.getCode());
                        supplierNoticeVO.setReduceOperateType(EnhanceSupplierOperateTypeEnum.TO_BE_COMMIT.getCode());
                        supplierNoticeVO.setReduceCount(1L);
                        noticeVOList.add(supplierNoticeVO);
                        //确认生产通知单 - 待提交审核生产通知单 - 待办加1
                        OperateNoticeVO processNoticeVO = new OperateNoticeVO();
                        processNoticeVO.setMemberId(p.getProcessMemberId());
                        processNoticeVO.setRoleId(p.getProcessRoleId());
                        processNoticeVO.setDataSource(OperateDataSourceEnum.ENHANCE_PROCESS.getCode());
                        processNoticeVO.setIncreaseOperateType(EnhanceProcessOperateTypeEnum.TO_BE_VALIFY_COMMIT.getCode());
                        processNoticeVO.setIncreaseCount(1L);
                        noticeVOList.add(processNoticeVO);

                        //SystemMessageRequest集合加1
                        SystemMessageRequest systemMessageRequest = new SystemMessageRequest();
                        systemMessageRequest.setMemberId(p.getProcessMemberId());
                        systemMessageRequest.setRoleId(p.getProcessRoleId());
                        systemMessageRequest.setMessageNotice(MessageTemplateCode.production_order_handle_wait_audit);
                        systemMessageRequest.setParams(Stream.of(p.getNoticeNo(), p.getSummary()).collect(Collectors.toList()));
                        systemMessageRequestList.add(systemMessageRequest);
                    }else {
                        //保存成功的生产通知单需要调用报表服务和消息服务 -> 新增操作通知、批量发送系统消息
                        if(CollectionUtil.isNotEmpty(noticeVOList)) {
                            reportAsyncService.addOperateNoticeList(noticeVOList);
                            messageAsyncService.batchSendSystemMessage(systemMessageRequestList);
                        }
                        log.error("执行外部工作流程任务失败, 导致生产通知单的任务ID与工作流服务的任务ID不匹配【异常生产通知单】");
                        log.error("工作流服务异常:" + outerWrapper.getMessage());
                        return Wrapper.fail(ResponseCode.ENHANCE_WORKFLOW_ERROR);
                    }
                }else {
                    //保存成功的生产通知单需要调用报表服务和消息服务 -> 新增操作通知、批量发送系统消息
                    if(CollectionUtil.isNotEmpty(noticeVOList)) {
                        reportAsyncService.addOperateNoticeList(noticeVOList);
                        messageAsyncService.batchSendSystemMessage(systemMessageRequestList);
                    }
                    log.error("开启加工企业内部工作流失败, 导致生产通知单的任务ID与工作流服务的任务ID不匹配【异常生产通知单】");
                    log.error("工作流服务异常:" + processWrapper.getMessage());
                    return Wrapper.fail(ResponseCode.ENHANCE_WORKFLOW_ERROR);
                }
            }else {
                log.error("工作流服务异常:" + supplierWrapper.getMessage());
                return Wrapper.fail(ResponseCode.ENHANCE_WORKFLOW_ERROR);
            }
        }

        //调用报表服务、消息服务 -> 批量新增操作通知、批量发送系统消息（如果调用过程出现异常, 无需回滚, 直接catch打印日志正常返回。）
        reportAsyncService.addOperateNoticeList(noticeVOList);
        messageAsyncService.batchSendSystemMessage(systemMessageRequestList);

        return Wrapper.success();
    }
}
